package com.easylinkin.linkappapi.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easylinkin.linkappapi.annotation.CommonOperateLogAnnotate;
import com.easylinkin.linkappapi.common.utils.CharCompressUtil;
import com.easylinkin.linkappapi.operatelog.LogHelper;
import com.easylinkin.linkappapi.operatelog.entity.CommonOperateLog;
import com.easylinkin.linkappapi.operatelog.service.CommonOperateLogService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

@Component
@Aspect
@Slf4j
public class CommonOperationLogAspect {

    @Resource
    private CommonOperateLogService commonOperateLogService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    private static int charLength = 30000;

    @Pointcut("@annotation(com.easylinkin.linkappapi.annotation.CommonOperateLogAnnotate)")
    private void pointcut() {
    }


    @AfterReturning(pointcut = "pointcut() && @annotation(commonOperateLogAnnotate)", returning = "returnObj")
    public void doAfterReturning(JoinPoint joinPoint, CommonOperateLogAnnotate commonOperateLogAnnotate, Object returnObj) {
        String content = commonOperateLogAnnotate.desc();
        String supplement = LogHelper.getContent();
        if(StringUtils.isNotEmpty(supplement)){
            content = content + supplement;
        }
        CommonOperateLog commonOperateLog = new CommonOperateLog(commonOperateLogAnnotate.module().getName(), content);
        // 获取request
        HttpServletRequest request =
            ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if(null == request){
            return;
        }
        String platform = request.getHeader("platform");
        if(StringUtils.isNotEmpty(platform)){
            commonOperateLog.setPlatform(platform);
        }
        LinkappUser current = linkappUserContextProducer.getCurrent();
        if (current != null) {
            commonOperateLog.setUserAccount(current.getUsername());
            commonOperateLog.setTenantId(current.getTenantId());
            commonOperateLog.setPhone(current.getPhone());
            commonOperateLog.setNickname(current.getNickname());
        }
        doAfterReturning(joinPoint, commonOperateLogAnnotate, returnObj, commonOperateLog);
        LogHelper.clearContent();
    }

    @Async
    public void doAfterReturning(JoinPoint joinPoint, CommonOperateLogAnnotate commonOperateLogAnnotate, Object returnObj, CommonOperateLog commonOperateLog) {
        if (returnObj != null) {
            String jsonStr = JSON.toJSONString(returnObj);
            commonOperateLog.setResultContent(JSON.toJSONString(returnObj));
            JSONObject jsonObject = JSONObject.parseObject(jsonStr);
            Boolean isSuccess = jsonObject.getBoolean("success");
            commonOperateLog.setResult(isSuccess);
        }else{
            // 返回为空时默认为成功
            commonOperateLog.setResult(true);
        }
        addCommonOperationLog(joinPoint, commonOperateLogAnnotate, commonOperateLog);
    }

    @AfterThrowing(pointcut = "pointcut() && @annotation(commonOperateLogAnnotate)", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, CommonOperateLogAnnotate commonOperateLogAnnotate, Exception ex) {
        String content = commonOperateLogAnnotate.desc();
        String supplement = LogHelper.getContent();
        if(StringUtils.isNotEmpty(supplement)){
            content = content + supplement;
        }
        CommonOperateLog commonOperateLog = new CommonOperateLog(commonOperateLogAnnotate.module().getName(), content);
        // 获取request
        HttpServletRequest request =
            ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if(null == request){
            return;
        }
        String platform = request.getHeader("platform");
        if(StringUtils.isNotEmpty(platform)){
            commonOperateLog.setPlatform(platform);
        }
        LinkappUser current = linkappUserContextProducer.getCurrent();
        if (current != null) {
            commonOperateLog.setUserAccount(current.getUsername());
            commonOperateLog.setTenantId(current.getTenantId());
            commonOperateLog.setPhone(current.getPhone());
            commonOperateLog.setNickname(current.getNickname());
        }
        doAfterThrowing(joinPoint, commonOperateLogAnnotate, ex, commonOperateLog);
        LogHelper.clearContent();
    }

    @Async
    public void doAfterThrowing(JoinPoint joinPoint, CommonOperateLogAnnotate commonOperateLogAnnotate, Exception ex, CommonOperateLog commonOperateLog) {
        if (ex != null) {
            commonOperateLog.setResultContent("异常信息：" + ex.toString());
        }
        commonOperateLog.setResult(false);
        addCommonOperationLog(joinPoint, commonOperateLogAnnotate, commonOperateLog);
    }

    public void addCommonOperationLog(JoinPoint joinPoint, CommonOperateLogAnnotate commonOperateLogAnnotate, CommonOperateLog commonOperateLog) {
        // 参数
        if (commonOperateLogAnnotate.recordParam() && joinPoint.getArgs() != null) {
            Object[] args = joinPoint.getArgs();
            Stream<?> stream = ArrayUtils.isEmpty(args) ? Stream.empty() : Arrays.asList(args).stream();
            List<Object> logArgs = stream
                .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse) && !(arg instanceof MultipartFile)))
                .collect(Collectors.toList());
            //过滤后序列化无异常
            String string = JSON.toJSONString(logArgs);
            if(StringUtils.isNotEmpty(string) && string.length() > charLength){
                try {
                    string = CharCompressUtil.compressWrap(string);
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            commonOperateLog.setParams(string);
        }
        commonOperateLogService.addLog(commonOperateLog);

    }


}
